/**
 * Copyright 2009 Jesse Brown (jbrown@fluentv.com)
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); 
 * you may not use this file except in compliance with the License. 
 * You may obtain a copy of the License at 
 *   http://www.apache.org/licenses/LICENSE-2.0 
 * 
 * Unless required by applicable law or agreed to in writing, software 
 * distributed under the License is distributed on an "AS IS" BASIS, 
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
 * See the License for the specific language governing permissions and 
 * limitations under the License. 
 */
package com.fluentv.games.netblocks;

import android.util.Log;
import android.view.GestureDetector;
import android.view.MotionEvent;

import com.fluentv.games.netblocks.PlayingField.MoveDirection;

/**
 * Gesture detector. React when various high level gestures occur.
 * 
 * @author Jesse Brown (jbrown@fluentv.com)
 */
public class GestureMovementListener implements GestureDetector.OnGestureListener {
  
  private final PlayingField playingField;
  private transient SoundEffectsPlayer soundEffects;
  private float pendingMovementX = 0.0f;
  private float pendingMovementY = 0.0f;
  
  // Multiply movement by amount to adjust sensitivity. Increases sensitivity when > 1.
  private static float HORIZ_SENSITIVITY = 1.1f;
  private static float VERT_SENSITIVITY = 1.5f;
  
  public GestureMovementListener(SoundEffectsPlayer soundEffects, PlayingField playingField) {
    this.soundEffects = soundEffects;
    this.playingField = playingField;    
  }
  
  @Override
  public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX,
      float distanceY) {
    
    scaledMovement(distanceX, distanceY);
    return true;
  }

  @Override
  public boolean onSingleTapUp(MotionEvent e) {
    // Make sure the tap maps to the area outside out buttons (i.e. bottom of the playing field on up)
    if (e.getY() > playingField.getBottom()) {
      return false;
    }
    
    if (!playingField.rotateCurrentShape()) {
      soundEffects.rotateBlockFailed();
    } else {
      soundEffects.rotateBlockSuccess();
    }
    return true;
  }        
  
  private void scaledMovement(float movementX, float movementY) {
    
    pendingMovementX += movementX * HORIZ_SENSITIVITY;
    pendingMovementY += movementY * VERT_SENSITIVITY;
    
    int cellWidth = (playingField.getWidth() / playingField.getCellsWide());
    int cellHeight = (playingField.getHeight() / playingField.getCellsHigh());
    
    Log.v("GestureMovement", "Relative movement X " + movementX + ", Y " + movementY 
        + " - Cell width: " + cellWidth + ", Height: " + cellHeight);

    
    if (Math.abs(pendingMovementX) > cellWidth) {
      int times = (int) (Math.abs(pendingMovementX) / cellWidth); 
      if (pendingMovementX > 0) {
        move(times, MoveDirection.LEFT);
      } else if (pendingMovementX < 0) {        
        move(times, MoveDirection.RIGHT);         
      }
      pendingMovementX = 0; 
    } 

    if (Math.abs(pendingMovementY) > cellHeight) {
      int times = (int) (Math.abs(pendingMovementY) / cellHeight);
      if (pendingMovementY < 0) {
        move(times, MoveDirection.DOWN);
      }
      pendingMovementY = 0;
    }
    
  }
  
  private void move(int times, MoveDirection direction) {
    for (int i = 0; i < times; i++) {
      if (playingField.moveCurrentShape(direction)) {
        soundEffects.moveBlockSuccess();
      } else {
        soundEffects.moveBlockFailed();
      }
    }
  }

  @Override
  public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
      float velocityY) {  
    return true;
  }

  @Override
  public boolean onDown(MotionEvent e) {    
    return true;
  }

  @Override
  public void onLongPress(MotionEvent e) {
  }

  @Override
  public void onShowPress(MotionEvent e) { 
  }
}